package com.study.util;

import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.util.*;

public class HttpUtils {

    // 编码格式。发送编码格式统一用UTF-8
    private static final String ENCODING = "UTF-8";

    // 设置连接超时时间，单位毫秒。
    private static final int CONNECT_TIMEOUT = 6000;

    // 请求获取数据的超时时间(即响应时间)，单位毫秒。
    private static final int SOCKET_TIMEOUT = 6000;

    /**
     * get请求方式
     * @param url 路径加参数拼接
     * @return
     */
    public static String sendGet(String url) {

        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;

        try {
            httpClient = HttpClients.createDefault();
            HttpGet httpGet = new HttpGet(url);
            /**
             * setConnectTimeout：设置连接超时时间，单位毫秒。
             * setConnectionRequestTimeout：设置从connect Manager(连接池)获取Connection
             * 超时时间，单位毫秒。这个属性是新加的属性，因为目前版本是可以共享连接池的。
             * setSocketTimeout：请求获取数据的超时时间(即响应时间)，单位毫秒。 如果访问一个接口，多少时间内无法返回数据，就直接放弃此次调用。
             */
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT)
                    .setSocketTimeout(SOCKET_TIMEOUT).build();
            httpGet.setConfig(requestConfig);

            response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();

            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String result = EntityUtils.toString(entity, ENCODING);
                return result;
            }
            return "error," + response.getStatusLine().getStatusCode();
        } catch (IOException e) {
            e.printStackTrace();
            return e.getMessage();
        } finally {
            try {
                response.close();
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * get请求方式
     * @param url 请求路径
     * @param params 请求参数
     * @param <T>
     * @return
     */
    public static <T extends Map> String sendGet(String url, T params){
        Iterator<Map.Entry<String, Object>> iterator = params.entrySet().iterator();
        StringBuffer sb = new StringBuffer("?");
        while(iterator.hasNext()){
            Map.Entry<String, Object> next = iterator.next();
            String key = next.getKey();
            String val = next.getValue().toString();
            sb.append(key).append("=").append(val).append("&");
        }
        sb.deleteCharAt(sb.length()-1);
        return sendGet(url + sb.toString());
    }

    /**
     * post请求方式 json串传值
     * @param url
     * @param jsonStr
     * @return
     */
    public static String sendPostJSON(String url,String jsonStr){
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        try {
            httpClient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost(url);
            StringEntity entity = new StringEntity(jsonStr,ENCODING);
            entity.setContentEncoding(ENCODING);
            entity.setContentType("application/json");
            httpPost.setEntity(entity);
            /**
             * setConnectTimeout：设置连接超时时间，单位毫秒。
             * setConnectionRequestTimeout：设置从connect Manager(连接池)获取Connection
             * 超时时间，单位毫秒。这个属性是新加的属性，因为目前版本是可以共享连接池的。
             * setSocketTimeout：请求获取数据的超时时间(即响应时间)，单位毫秒。 如果访问一个接口，多少时间内无法返回数据，就直接放弃此次调用。
             */
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT)
                    .setSocketTimeout(SOCKET_TIMEOUT).build();
            httpPost.setConfig(requestConfig);

            response = httpClient.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == 200) {
                String result = EntityUtils.toString(response.getEntity(), ENCODING);
                return result;
            }
            return "error," + response.getStatusLine().getStatusCode();
        }catch (Exception e){
            e.printStackTrace();
            return e.getMessage();
        }finally {
            try {
                response.close();
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static String sendPostForm(String url,List<NameValuePair> nvps){
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        try {
            httpClient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost(url);

            httpPost.setEntity(new UrlEncodedFormEntity(nvps, ENCODING));
            /**
             * setConnectTimeout：设置连接超时时间，单位毫秒。
             * setConnectionRequestTimeout：设置从connect Manager(连接池)获取Connection
             * 超时时间，单位毫秒。这个属性是新加的属性，因为目前版本是可以共享连接池的。
             * setSocketTimeout：请求获取数据的超时时间(即响应时间)，单位毫秒。 如果访问一个接口，多少时间内无法返回数据，就直接放弃此次调用。
             */
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT)
                    .setSocketTimeout(SOCKET_TIMEOUT).build();
            httpPost.setConfig(requestConfig);

            response = httpClient.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == 200) {
                String result = EntityUtils.toString(response.getEntity(), ENCODING);
                return result;
            }
            return "error," + response.getStatusLine().getStatusCode();
        }catch (Exception e){
            e.printStackTrace();
            return e.getMessage();
        }finally {
            try {
                response.close();
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * post请求方式 表单传递
     * @param url 请求路径
     * @param params 集合参数
     * @param <T>
     * @return
     */
    public static <T extends Map> String sendPostForm(String url,T params){
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        Set<String> keySet = params.keySet();
        for (String key : keySet) {
            nvps.add(new BasicNameValuePair(key, String.valueOf(params.get(key))));
        }
        return sendPostForm(url,nvps);
    }

    /**
     * webservice请求方式
     * @param url 请求路径
     * @param soap webservice请求参数(可以从soapUI中直接提取)
     * @return
     *
     * 入参样例：<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.zzj.com"><soapenv:Header/><soapenv:Body><ser:savePatientInfo><!--Optional:--><reqParams><![CDATA[<resquest><flag>person</flag></resquest>]]></reqParams></ser:savePatientInfo></soapenv:Body></soapenv:Envelope>
     * 出参样例：<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:savePatientInfoResponse xmlns:ns2="http://service.zzj.com"><return>&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;Response&gt;&lt;ResultCode&gt;0&lt;/ResultCode&gt;&lt;ResultContent&gt;建档完成&lt;/ResultContent&gt;&lt;/Response&gt;</return></ns2:savePatientInfoResponse></soap:Body></soap:Envelope>
     */
    public static String sendWebService(String url,String soap){
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        try {
            httpClient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost(url);
//            httpPost.setHeader("Content-Type","text/xml;charset=UTF-8");

//            InputStreamEntity entity = new InputStreamEntity(new ByteArrayInputStream(soap.getBytes("UTF-8")));
            StringEntity entity = new StringEntity(soap,ENCODING);
            entity.setContentEncoding(ENCODING);
            entity.setContentType("text/xml");
            httpPost.setEntity(entity);

            response = httpClient.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == org.apache.http.HttpStatus.SC_OK) {
                HttpEntity responseEntity = response.getEntity();
                String back = EntityUtils.toString(responseEntity,ENCODING);
                return back;
            }
            return "error," + response.getStatusLine().getStatusCode();
        }catch (Exception e){
            e.printStackTrace();
            return e.getMessage();
        }finally {
            try {
                response.close();
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
